package com.liyuxiang.graph.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class DepartmentRecommendationService {

    private static final Logger logger = LoggerFactory.getLogger(DepartmentRecommendationService.class);
    private final ChatClient chatClient;
    private final ObjectMapper objectMapper;

    private static final String DEPARTMENT_RECOMMENDATION_PROMPT = """
            您是一位资深的医疗分诊专家，拥有丰富的临床经验。请根据患者的症状信息，精准推荐最合适的科室。
            
               首先，请使用 getDeptList 工具获取最新的医院科室信息，然后基于科室专业范围进行分析。
               推荐科室后，请使用 addMedicalCase 工具自动保存患者的病例信息。
            
               患者症状信息：
               {symptoms}
            
               对话历史：
               {history}
            
               问诊轮次：{questionCount}
               用户ID：{userId}
            
               分析步骤：
               1. 使用 getDeptList 工具获取科室完整信息
               2. 识别主要症状和涉及的器官系统
               3. 评估症状的严重程度和紧急性
               4. 考虑患者的基本信息（年龄、性别）
               5. 分析症状的时间特点和发展趋势
               6. 识别需要多学科会诊的复杂情况
               7. 推荐科室后调用 addMedicalCase 工具保存病例记录
            
               工具使用说明：
               - 首先调用 getDeptList 工具获取最新的科室信息
               - 基于工具返回的科室数据进行专业分析
               - 推荐科室后必须调用 addMedicalCase 工具保存病例（patientId使用用户ID，deptId使用推荐科室ID，chiefComplaint使用症状总结）
               - 如果工具调用失败，使用您掌握的医疗知识进行推荐
            
               请严格按照以下JSON格式回复：
               {
                 "primaryDepartment": "主要推荐科室名称",
                 "deptId": "主要推荐科室ID",
                 "deptIds": ["主要推荐科室ID", "备选科室ID1", "备选科室ID2"],
                 "alternativeDepartments": ["备选科室1", "备选科室2"],
                 "confidence": 0.85,
                 "urgency": "medium",
                 "reasoning": "推荐理由",
                 "clinicalAdvice": "临床建议",
                 "redFlags": ["危险信号1", "危险信号2"],
                 "preparationTips": ["准备建议1", "准备建议2"],
                 "estimatedWaitCategory": "普通",
                 "followUpSuggestions": ["随访建议1", "随访建议2"]
               }
            
               注意事项：
               - 必须首先调用 getDeptList 工具
               - 推荐科室后必须调用 addMedicalCase 工具保存病例信息
               - 症状不明确时，优先推荐覆盖面较广的科室
               - 多系统症状考虑推荐内科作为首选
               - 发现危险征象时，必须推荐急诊科
               - 考虑患者的年龄和性别特点
               - 推荐理由要专业、详细、易懂
            """;

    public DepartmentRecommendationService(@Qualifier("simpleCharClientBuilder") ChatClient.Builder simpleCharClientBuilder, ObjectMapper objectMapper) {
        this.chatClient = simpleCharClientBuilder.build();
        this.objectMapper = objectMapper;
    }

    public DepartmentRecommendationResult recommendDepartment(Map<String, Object> symptoms, List<String> conversationHistory, int questionCount, String userId) {
        logger.info("开始AI科室推荐分析 - 用户ID: {}, 症状数量: {}, 问诊轮次: {}", userId, symptoms.size(), questionCount);

        try {
            String symptomsText = formatSymptoms(symptoms);
            String historyText = conversationHistory.isEmpty() ? "无对话历史" : String.join("\n", conversationHistory);

            String prompt = DEPARTMENT_RECOMMENDATION_PROMPT
                    .replace("{symptoms}", symptomsText)
                    .replace("{history}", historyText)
                    .replace("{questionCount}", String.valueOf(questionCount))
                    .replace("{userId}", userId);

            logger.info("发送科室推荐请求 - 症状信息长度: {}", symptomsText.length());

            String aiResponse = chatClient.prompt().user(prompt).toolNames("getDeptList", "addMedicalCase").call()
                                          .content();

            logger.info("收到AI科室推荐响应: {}", aiResponse);

            DepartmentRecommendationResult result = parseDepartmentRecommendationResponse(aiResponse);

            logger.info("科室推荐完成 - 用户ID: {}, 主推科室: {}, 主科室ID: {}, 推荐科室数量: {}, 紧急度: {}, 置信度: {}",
                    userId, result.getPrimaryDepartment(), result.getDeptId(), 
                    result.getDeptIds() != null ? result.getDeptIds().length : 0, result.getUrgency(), result.getConfidence());
            
            if (result.hasMultipleDepartments()) {
                logger.info("多科室推荐 - 科室IDs: {}, 备选科室: {}", 
                    java.util.Arrays.toString(result.getDeptIds()), 
                    java.util.Arrays.toString(result.getAlternativeDepartments()));
            }

            return result;

        } catch (Exception e) {
            logger.error("AI科室推荐失败 - 用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            return getFallbackDepartmentRecommendation(symptoms, userId);
        }
    }

    private DepartmentRecommendationResult parseDepartmentRecommendationResponse(String response) {
        try {
            int startIndex = response.indexOf('{');
            int endIndex = response.lastIndexOf('}') + 1;

            if (startIndex >= 0 && endIndex > startIndex) {
                String jsonStr = response.substring(startIndex, endIndex);
                JsonNode jsonNode = objectMapper.readTree(jsonStr);

                String primaryDepartment = jsonNode.get("primaryDepartment").asText("内科");

                // 修复deptId解析逻辑
                Long deptId = 0L;
                if (jsonNode.has("deptId")) {
                    JsonNode deptIdNode = jsonNode.get("deptId");
                    if (deptIdNode.isNumber()) {
                        deptId = deptIdNode.asLong();
                    } else if (deptIdNode.isTextual()) {
                        try {
                            deptId = Long.parseLong(deptIdNode.asText());
                        } catch (NumberFormatException e) {
                            logger.warn("deptId格式错误: {}", deptIdNode.asText());
                        }
                    }
                }

                // 解析deptIds数组
                Long[] deptIds = new Long[0];
                if (jsonNode.has("deptIds") && jsonNode.get("deptIds").isArray()) {
                    JsonNode deptIdsNode = jsonNode.get("deptIds");
                    java.util.List<Long> deptIdList = new java.util.ArrayList<>();
                    for (JsonNode idNode : deptIdsNode) {
                        try {
                            if (idNode.isNumber()) {
                                deptIdList.add(idNode.asLong());
                            } else if (idNode.isTextual()) {
                                deptIdList.add(Long.parseLong(idNode.asText()));
                            }
                        } catch (NumberFormatException e) {
                            logger.warn("deptIds中的ID格式错误: {}", idNode.asText());
                        }
                    }
                    deptIds = deptIdList.toArray(new Long[0]);
                }

                String[] alternativeDepartments = jsonNode.has("alternativeDepartments") && jsonNode.get("alternativeDepartments").isArray()
                        ? objectMapper.convertValue(jsonNode.get("alternativeDepartments"), String[].class)
                        : new String[]{};
                double confidence = jsonNode.has("confidence") ? jsonNode.get("confidence").asDouble(0.7) : 0.7;
                String urgency = jsonNode.has("urgency") ? jsonNode.get("urgency").asText("medium") : "medium";
                String reasoning = jsonNode.has("reasoning") ? jsonNode.get("reasoning").asText("基于症状分析推荐") : "基于症状分析推荐";
                String clinicalAdvice = jsonNode.has("clinicalAdvice") ? jsonNode.get("clinicalAdvice").asText("请及时就医") : "请及时就医";
                String[] redFlags = jsonNode.has("redFlags") && jsonNode.get("redFlags").isArray()
                        ? objectMapper.convertValue(jsonNode.get("redFlags"), String[].class)
                        : new String[]{};
                String[] preparationTips = jsonNode.has("preparationTips") && jsonNode.get("preparationTips").isArray()
                        ? objectMapper.convertValue(jsonNode.get("preparationTips"), String[].class)
                        : new String[]{};
                String estimatedWaitCategory = jsonNode.has("estimatedWaitCategory") ? jsonNode.get("estimatedWaitCategory").asText("普通") : "普通";
                String[] followUpSuggestions = jsonNode.has("followUpSuggestions") && jsonNode.get("followUpSuggestions").isArray()
                        ? objectMapper.convertValue(jsonNode.get("followUpSuggestions"), String[].class)
                        : new String[]{};

                return new DepartmentRecommendationResult(
                        primaryDepartment,
                        deptId,
                        deptIds,
                        alternativeDepartments,
                        confidence,
                        urgency,
                        reasoning,
                        clinicalAdvice,
                        redFlags,
                        preparationTips,
                        estimatedWaitCategory,
                        followUpSuggestions,
                        true
                );
            }
        } catch (Exception e) {
            logger.warn("解析科室推荐JSON失败，尝试文本解析: {}", e.getMessage());
        }

        return parseTextDepartmentResponse(response);
    }

    private DepartmentRecommendationResult parseTextDepartmentResponse(String response) {
        String primaryDepartment = extractDepartmentFromText(response);
        Long deptId = 0L;
        Long[] deptIds = new Long[]{0L};  // 默认单个科室ID
        String[] alternativeDepartments = {};
        String reasoning = "基于文本分析的推荐";
        String clinicalAdvice = "建议尽快就医，详细描述症状";

        return new DepartmentRecommendationResult(
                primaryDepartment,
                deptId,
                deptIds,
                alternativeDepartments,
                0.6,
                "medium",
                reasoning,
                clinicalAdvice,
                new String[]{},
                new String[]{},
                "普通",
                new String[]{},
                false
        );
    }

    private String extractDepartmentFromText(String response) {
        // 科室匹配优先级列表
        String[] departments = {"急诊科", "心内科", "呼吸内科", "消化内科", "神经内科", "内分泌科", "肾内科", "血液科", "风湿免疫科", "感染科", "老年科", "普外科", "骨科", "神经外科", "胸外科", "心外科", "泌尿外科", "肝胆外科", "血管外科", "整形外科", "烧伤科", "妇科", "产科", "儿科", "新生儿科", "眼科", "耳鼻喉科", "口腔科", "皮肤科", "精神科", "康复科", "中医科", "营养科", "内科", "外科"};

        for (String dept : departments) {
            if (response.contains(dept)) {
                logger.info("从回复中识别到科室: {}", dept);
                return dept;
            }
        }

        logger.warn("无法从回复中提取科室信息，使用默认推荐: 内科");
        return "内科";
    }

    private DepartmentRecommendationResult getFallbackDepartmentRecommendation(Map<String, Object> symptoms, String userId) {
        logger.warn("使用备用科室推荐逻辑 - 用户ID: {}", userId);

        String symptomsText = formatSymptoms(symptoms).toLowerCase();
        String primaryDepartment = "内科";
        Long deptId = 0L;
        Long[] deptIds = new Long[]{0L};  // 默认单个科室ID
        String[] alternativeDepartments = {"急诊科"};
        String reasoning = "备用分析：症状信息不足，推荐内科进行初步诊断";
        String urgency = "medium";
        String clinicalAdvice = "建议及时就医，详细向医生描述症状";
        String[] redFlags = {"症状加重", "新症状出现"};
        String[] preparationTips = {"携带身份证", "准备症状描述", "带上既往检查报告"};

        // 简单的关键词匹配
        if (symptomsText.contains("头痛") || symptomsText.contains("头晕") || symptomsText.contains("神经")) {
            primaryDepartment = "神经内科";
            alternativeDepartments = new String[]{"内科"};
            reasoning = "备用分析：检测到神经系统相关症状";
        } else if (symptomsText.contains("胸痛") || symptomsText.contains("心") || symptomsText.contains("心悸")) {
            primaryDepartment = "心内科";
            alternativeDepartments = new String[]{"急诊科"};
            reasoning = "备用分析：检测到心血管系统相关症状";
            urgency = "high";
            deptIds = new Long[]{1L, 2L};  // 心内科和急诊科
        } else if (symptomsText.contains("腹痛") || symptomsText.contains("胃") || symptomsText.contains("消化")) {
            primaryDepartment = "消化内科";
            alternativeDepartments = new String[]{"内科"};
            reasoning = "备用分析：检测到消化系统相关症状";
        } else if (symptomsText.contains("咳嗽") || symptomsText.contains("气") || symptomsText.contains("肺")) {
            primaryDepartment = "呼吸内科";
            alternativeDepartments = new String[]{"内科"};
            reasoning = "备用分析：检测到呼吸系统相关症状";
        }

        return new DepartmentRecommendationResult(
                primaryDepartment,
                deptId,
                deptIds,
                alternativeDepartments,
                0.6,
                urgency,
                reasoning,
                clinicalAdvice,
                redFlags,
                preparationTips,
                "普通",
                new String[]{"一周后复查"},
                false
        );
    }

    private String formatSymptoms(Map<String, Object> symptoms) {
        if (symptoms.isEmpty()) {
            return "症状信息不详";
        }

        StringBuilder sb = new StringBuilder();
        symptoms.forEach((key, value) -> {
            sb.append(key).append(": ").append(value).append("\n");
        });
        return sb.toString();
    }

    @Getter
    public static class DepartmentRecommendationResult {
        // Getters
        private final String primaryDepartment;
        private final Long deptId;
        private final Long[] deptIds;  // 支持多个科室ID的数组
        private final String[] alternativeDepartments;
        private final double confidence;
        private final String urgency;
        private final String reasoning;
        private final String clinicalAdvice;
        private final String[] redFlags;
        private final String[] preparationTips;
        private final String estimatedWaitCategory;
        private final String[] followUpSuggestions;
        private final boolean fullAiAnalysis;

        public DepartmentRecommendationResult(String primaryDepartment, Long deptId, Long[] deptIds, String[] alternativeDepartments,
                                              double confidence, String urgency, String reasoning,
                                              String clinicalAdvice, String[] redFlags, String[] preparationTips,
                                              String estimatedWaitCategory, String[] followUpSuggestions,
                                              boolean fullAiAnalysis) {
            this.primaryDepartment = primaryDepartment;
            this.deptId = deptId;
            this.deptIds = deptIds != null ? deptIds : new Long[]{deptId};  // 如果没有提供数组，则使用单个ID
            this.alternativeDepartments = alternativeDepartments;
            this.confidence = confidence;
            this.urgency = urgency;
            this.reasoning = reasoning;
            this.clinicalAdvice = clinicalAdvice;
            this.redFlags = redFlags;
            this.preparationTips = preparationTips;
            this.estimatedWaitCategory = estimatedWaitCategory;
            this.followUpSuggestions = followUpSuggestions;
            this.fullAiAnalysis = fullAiAnalysis;
        }

        public boolean isEmergency() {
            return "emergency".equals(urgency) || "high".equals(urgency);
        }

        public boolean hasMultipleDepartments() {
            return deptIds != null && deptIds.length > 1;
        }
    }
}